package com.atg.atgchat.init.websocket;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.atg.atgchat.init.websocket.model.enums.WebSocketRequestTypeEnum;
import com.atg.atgchat.init.websocket.serivce.WebSocketService;
import com.atg.atgchat.init.websocket.utils.NettyUtil;
import com.atg.atgchat.init.websocket.vo.resp.WebSocketBaseResp;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

/*
author: atg
time: 2025/1/11 22:14
*/
@Slf4j
@Sharable
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Resource
    private WebSocketService webSocketService;

    /**
     * 添加处理器
     *
     * @param ctx
     * @throws Exception
     */
    // 当web客户端连接后，触发该方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        this.webSocketService = getService();
    }

    private WebSocketService getService() {
        return SpringUtil.getBean(WebSocketService.class);
    }

    // 客户端下线
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        userOffline(ctx.channel());
    }

    /**
     * 心跳检查
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            System.out.println("握手成功");
            // 建立连接
            webSocketService.channelConnect(ctx.channel());
            String token = NettyUtil.getAttr(ctx.channel(), NettyUtil.TOKEN);
            if (StrUtil.isNotBlank(token)) {
                this.webSocketService.authorize(ctx.channel(), token);
            }
//            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
//            // 读空闲
//            if (idleStateEvent.state() == IdleState.READER_IDLE) {
//                // 关闭用户的连接
//                userOffline(ctx.channel());
//            }
        } else if (evt instanceof IdleStateEvent) {

            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                // 关闭用户的连接
                userOffline(ctx.channel());
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    // 用户下线
    private void userOffline(Channel channel) {
        webSocketService.offLine(channel);
        channel.close();
    }


    /**
     * 处理异常
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.warn("异常发生, 异常消息 = {}", cause.toString());
        ctx.channel().close();
    }

    /**
     * 读取客户端发送的请求报文
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *            belongs to
     * @param msg the message to handle
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        String text = msg.text();
        WebSocketBaseResp wsBaseRep = JSONUtil.toBean(text, WebSocketBaseResp.class);
        WebSocketRequestTypeEnum wsReqTypeEnum = WebSocketRequestTypeEnum.of(wsBaseRep.getType());
        switch (wsReqTypeEnum) {
            case LOGIN:
                webSocketService.handLoginRequest(ctx.channel());
                break;
            case HEART_BEAT:
                break;
            case AUTHORIZE:
                String data = wsBaseRep.getData().toString();
                webSocketService.authorize(ctx.channel(), data);
        }
    }
}

